package com.xbn.netty.nettyHeartBeat;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;

import java.util.concurrent.TimeUnit;

/**
 * @author XBN
 * @date 2020/10/21 18:36
 * @email 78742541@qq.com
 */
/*
* 心跳连接服务器，客户端直接使用群聊系统客户端即可
* */
public class MyServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup=new NioEventLoopGroup(1);
        EventLoopGroup workerGroup=new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))//在bossGroup中增加一个日志处理器
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //加入一个netty提供IdleStateHandler
                            /*
                            * 1、IdleStateHandler是netty处理空闲状态的处理器
                            * long readerIdleTime：表示服务器多长时间没有读取到数据，就会发送一个而心跳检测包，检测是否还是连接的状态
                            * long writeIdleTime:表示多长时间没有写，发送一个心跳检测包检测是否仍然处于连接状态
                            * long allIdleTime:表示多长时间没有读写，发送一个心跳检测包检测是否仍然处于连接状态
                            *
                            * 文档说明：Triggers an {@link IdleStateEvent} when a {@link Channel} has not performed
                             * read, write, or both operation for a while.
                             * 意思是触发一个时间当channel没有执行读、写、或者两者读没有执行就会触发一个事件
                             *
                             * 当IdleStateHandler的事件触发后，就会传递给管道的下一个handler去处理
                             * 通过回调触发下一个handler的userEventTigger，在该方法中去处理IdleStateHandler的事件
                             * 事件可能是读空闲、写空闲、读写空闲
                            * */
                            pipeline.addLast(new IdleStateHandler(3,5,7, TimeUnit.SECONDS));
                            //加入一个对空闲检测进一步处理的handler（自定义）
                            pipeline.addLast(new MyServerHeartHandler());
                        }
                    });
            //启动服务器
            ChannelFuture channelFuture = serverBootstrap.bind(7000).sync();
            //关闭监测，阻塞主线程等待子线程运行
            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
